#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
#include <cerrno>
#include <vector>
#include <time.h>
//判断是否是linux系统还是Windows的系统
#ifdef _WIN32
	#include <Windows.h>
#else 
	#include <unistd.h>
	#include <sys/mman.h>
#endif

// 展开常用的，防止命名污染
using std::cout;
using std::endl;
// 内存块的数量声明 
static const size_t NUM = 1024;
// 封装系统调用
inline static void* SystemAlloc(size_t kpage)
{
#ifdef _WIN32
	// windows下调用的申请内存的函数
	void* ptr = VirtualAlloc(0, kpage * (1 << 12), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	// 判断一下是否出错
	if (ptr == nullptr)
		throw std::bad_alloc();
#else
	// 调用系统调用linux下的brk等
	void* ptr = sbrk(kpage * (1 << 12));
	// 判断一下是否出错
	if (ptr == (void*)(-1))
		throw std::bad_alloc();
#endif
	return ptr;
}
// 定长内存池，可修改内存池的大小
template<class T>
class Fixed_Length
{
public:
	T* New()
	{
		T* Obj = nullptr;
		// 检测一下自由链表是否为空，如果为空，再申请空间，否则直接分配自由链表的内存块即可
		if (_freelist)
		{
			// 直接进行头删
			Obj = reinterpret_cast<T*>(_freelist);
			_freelist = *reinterpret_cast<void**>(_freelist);
			return Obj;
		}
		// _remain为0，说明此时已经没有可用的内存块了，应该更新
		else if (_remain < sizeof(T))
		{
			_start = reinterpret_cast<char*>(SystemAlloc((sizeof(T) * NUM) >> 12));
			//cout << (void*)_start << endl;
			// malloc失败，打印错误并且异常退出
			if (_start == nullptr)
			{
				throw std::bad_alloc();
			}
			// 成功在更新_remain
			_remain = ((sizeof(T) * NUM) >> 12) << 12;
		}
		// 进行内存分割
		Obj = reinterpret_cast<T*>(_start);
		// 定位new，进行对象初始化
		new(Obj)T;
		// 让_start往后走一个内存块，前面的内存块已经分配
		_start += sizeof(T) > sizeof(void*) ? sizeof(T) : sizeof(void*);
		// 减少剩余的内存块数量
		_remain -= sizeof(T) > sizeof(void*) ? sizeof(T) : sizeof(void*);
		// 返回申请内存的首地址
		return Obj;
	}
	void Delete(T* ptr)
	{
		// 显示调用析构函数
		ptr->~T();
		// 回收内存块的时候直接进行头插，可避免判断_freelist是否为空
		*reinterpret_cast<void**>(ptr) = _freelist;
		_freelist = reinterpret_cast<void*>(ptr);
	}
private:
	// 指向开始的内存块的大小
	char* _start = nullptr;
	// 自由链表，功能是指向回收的内存块
	void* _freelist = nullptr;
	// 剩余多少个T类型的内存块
	size_t _remain = 0;
};
struct TreeNode
{
	int _val;
	TreeNode* _left;
	TreeNode* _right;
	TreeNode()
		:_val(0)
		, _left(nullptr)
		, _right(nullptr)
	{}
};
